const http = require('http');
const { sm4 } = require('sm-crypto');
const cron = require('node-cron');
const moment = require('moment');
const os = require('os');
const axios = require('axios');

module.exports = app => {
  app.beforeStart(async () => {
    if (app.config.configCenterPlug) {
      const config = await init(app.config.configCenterPlug);
      app.config = Object.assign(app.config, config);
      const info = {
        ip: os.hostname(),
        mac: os.networkInterfaces(),
        app: app.config.appName,
        port: app.config.cluster.listen.port,
        platform: os.platform(),
        arch: os.arch(),
        release: os.release(),
        totalmem: os.totalmem(),
        freemem: os.freemem(),
        cpus: os.cpus(),
      };

      const options = {
        baseURL: `http://${app.config.health.host}:${app.config.health.port}`,
        url: '/healthCheck',
        method: 'POST',
        data: info,
      };

      if (app.config.health.enable) {
        const check_health_task = cron.schedule('*/10 * * * * *', async () => {
          console.log(`[${moment().format('YYYY-MM-DD HH:mm:ss')}]: 开始健康检查`);
          try {
            const data = await axios(options);

            if (data.status === 200) {
              console.log('========================== 注册成功 =========================');
            } else {
              throw new Error('注册时失败');
            }
          } catch (error) {
            console.log('================================= 注册失败 =============================');
          }
        });

        check_health_task.start();
      }
    }
  });
};

/**
 * 获取配置中心文件地址
 * @param {Object} params
 * @param {String} params.hostname
 * @param {String} params.port
 * @param {String} param.path
 * @param {String} param.method
 * @return
 */
async function init(params) {

  try {
    // 获取解密密钥
    const sd = await getSM(params.hostname, params.port);

    const enC = await getConfig(params.hostname, params.port, params.app, params.env);
    const decryptData = sm4.decrypt(enC.data, sd.key, { mode: sd.mode, iv: sd.iv });
    return JSON.parse(decryptData);
  } catch (error) {
    throw error;
  }

}

async function getConfig(hostname, port, app, env) {
  const options = {
    hostname,
    port,
    path: `/config/decrypt/info?app=${app}&env=${env}`,
    method: 'GET',
  };

  try {
    let data = await send(options);
    data = JSON.parse(data);
    if (data.code !== 200) {
      throw new Error('获取配置文件出错');
    }
    return data.data;
  } catch (error) {
    throw error;
  }
}

async function getSM(hostname, port) {
  const options = {
    hostname,
    port,
    path: '/config/sm/info',
    method: 'GET',
  };

  try {
    let data = await send(options);

    data = JSON.parse(data);

    if (data.code !== 200) {
      throw new Error('获取配置文件出错');
    }
    return data.data;
  } catch (error) {
    throw error;
  }
}

function send(options) {
  return new Promise((resolve, reject) => {
    const req = http.request(options, res => {
      let data = '';
      res.on('data', chunk => {
        data += chunk;
      });

      res.on('error', err => {
        reject(err);
      });

      res.on('end', () => {
        resolve(data);
      });
    });

    req.end();
  });
}
